package val.to.UI;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import val.to.ErrorHelper;
import val.to.R;
import val.to.ValtoServices;
import val.to.entities.Event;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

public class CreateEvent extends ListActivity {
	final int NAME_DIALOG_ID = 0;
	final int DESCRIPTION_DIALOG_ID = 1;
	final int DATE_DIALOG_ID = 2;
	final int TIME_DIALOG_ID = 3;
	final int DURATION_DIALOG_ID = 4;
	final int LOCATION_DIALOG_ID = 5;
	final int PRIVATE_EVENT_DIALOG_ID = 6;
	final int DIALOG_PADDING = 10;

	ArrayList<String> mLocationResults = new ArrayList<String>();

	Handler mHandler;
	int mYear, mMonth, mDay, mHour, mMinute, mDurationHour, mDurationMinute,
			mLocationLon = Integer.MAX_VALUE, mLocationLat = Integer.MAX_VALUE;
	ArrayList<ListItem> mDisplayData;
	String mName = "", mDescription = "", mPassword;
	boolean mPrivateEvent;
	EventsAdapter mAdapter;
	DatePickerDialog.OnDateSetListener mDateSetListener;
	OnTimeSetListener mTimeSetListener;
	MenuButton mMenuButton;
	ListView mList;
	Event mExistingEvent;
	LinearLayout createEventToolbar;
	LinearLayout editEventToolbar;
	LinearLayout mainLayout;

	private class ListItem {
		String Title;
		String Value;

		public ListItem(String title, String value) {
			super();
			Title = title;
			Value = value;
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.create_event);
		mHandler = new Handler();

		Bundle bundle = getIntent().getExtras();
		if (bundle != null) {
			mExistingEvent = bundle.getParcelable("val.to.entities.Event");
		}

		mDisplayData = buildData();

		mList = (ListView) findViewById(android.R.id.list);
		mList.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1,
					int position, long arg3) {

				if (position != LOCATION_DIALOG_ID)
					showDialog(position);
				else {
					Intent i = new Intent(arg1.getContext(),
							LocationChooser.class);
					if (mLocationLat != Integer.MAX_VALUE) {
						i.putExtra("Lat", mLocationLat);
						i.putExtra("Lon", mLocationLon);
					}
					startActivityForResult(i, 2);
				}
			}
		});

		mAdapter = new EventsAdapter(this, R.layout.create_event_item,
				mDisplayData);
		mList.setAdapter(mAdapter);

		mDateSetListener = new DatePickerDialog.OnDateSetListener() {
			@Override
			public void onDateSet(DatePicker view, int year, int monthOfYear,
					int dayOfMonth) {
				if (!isValidDate(year, monthOfYear, dayOfMonth, mHour, mMinute)) {
					Toast.makeText(view.getContext(),
							"The chosen date is invalid", Toast.LENGTH_SHORT)
							.show();
					return;
				}
				mYear = year;
				mMonth = monthOfYear;
				mDay = dayOfMonth;
				updateDisplay();
			}
		};

		mTimeSetListener = new OnTimeSetListener() {
			@Override
			public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
				if (!isValidDate(mYear, mMonth, mDay, hourOfDay, minute)) {
					Toast.makeText(view.getContext(),
							"The chosen time is inavlid", Toast.LENGTH_SHORT)
							.show();
					return;
				}
				mHour = hourOfDay;
				mMinute = minute;
				updateDisplay();
			}
		};

		if (mExistingEvent != null) {
			mName = mExistingEvent.getName();
			mDescription = mExistingEvent.getDescription();
			mLocationLat = (int) (mExistingEvent.getLatitude() * 1E6);
			mLocationLon = (int) (mExistingEvent.getLongitude() * 1E6);
			mYear = mExistingEvent.getStartDate().getYear() + 1900;
			mMonth = mExistingEvent.getStartDate().getMonth();
			mDay = mExistingEvent.getStartDate().getDate();
			mHour = mExistingEvent.getStartDate().getHours();
			mMinute = mExistingEvent.getStartDate().getMinutes();
			mDurationHour = (int) ((mExistingEvent.getEndTime().getTime() - mExistingEvent
					.getStartDate().getTime()) / 1000 / 60 / 60);
		} else {
			final Calendar c = Calendar.getInstance();
			mYear = c.get(Calendar.YEAR);
			mMonth = c.get(Calendar.MONTH);
			mDay = c.get(Calendar.DAY_OF_MONTH);
			mHour = c.get(Calendar.HOUR_OF_DAY);
			mMinute = c.get(Calendar.MINUTE);
			mDurationHour = 2;
		}
		updateDisplay();

		mMenuButton = (MenuButton) findViewById(R.id.menuButton);
		mMenuButton.init(this);

		createEventToolbar = (LinearLayout) findViewById(R.id.createToolbarLayout);
		editEventToolbar = (LinearLayout) findViewById(R.id.editToolbarLayout);
		mainLayout = (LinearLayout) findViewById(R.id.mainLayout);

		if (mExistingEvent == null) {
			editEventToolbar.setVisibility(View.GONE);

			Button createButton = (Button) findViewById(R.id.createEventButton);
			createButton.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					if (!verifyInput())
						return;
					AddEventTask task = new AddEventTask(v.getContext());

					Calendar c = Calendar.getInstance();
					c.set(mYear, mMonth, mDay, mHour, mMinute);
					Date start = c.getTime();
					c.add(Calendar.MINUTE, mDurationMinute);
					c.add(Calendar.HOUR, mDurationHour);
					Event event = null;
					if (mPrivateEvent)
						event = Event.NewEvent(mName, mDescription,
								mLocationLon / 1E6, mLocationLat / 1E6, start,
								c.getTime(), mPassword);
					else
						event = Event.NewEvent(mName, mDescription,
								mLocationLon / 1E6, mLocationLat / 1E6, start,
								c.getTime());
					task.execute(event);
				}
			});
		} else {
			createEventToolbar.setVisibility(View.GONE);

			Button updateButton = (Button) findViewById(R.id.updateEventButton);
			updateButton.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					if (!verifyInput())
						return;
					UpdateEventTask task = new UpdateEventTask(v.getContext());

					Calendar c = Calendar.getInstance();
					c.set(mYear, mMonth, mDay, mHour, mMinute);
					Date start = c.getTime();
					c.add(Calendar.MINUTE, mDurationMinute);
					c.add(Calendar.HOUR, mDurationHour);
					Event event = Event.UpdatedEvent(mExistingEvent.getId(),
							mName, mDescription, mLocationLon / 1E6,
							mLocationLat / 1E6, start, c.getTime());
					task.execute(event);
				}
			});

			Button deleteButton = (Button) findViewById(R.id.deleteEventButton);
			deleteButton.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					DeleteEventTask task = new DeleteEventTask(v.getContext());
					task.execute(mExistingEvent);
				}
			});
		}
	}

	private boolean isValidDate(int year, int month, int day, int hour,
			int minute) {
		Calendar c = Calendar.getInstance();
		c.set(year, month, day, hour, minute);
		// if (current.after(c))
		// return false; allow creating or updating event start date in the past
		return true;
	}

	private boolean verifyInput() {
		if (mName.trim().equals(""))
			Toast.makeText(this, "You must set the event's name",
					Toast.LENGTH_SHORT).show();
		else if (mDescription.trim().equals(""))
			Toast.makeText(this, "You must set the event's description",
					Toast.LENGTH_SHORT).show();
		else if (!isValidDate(mYear, mMonth, mDay, mHour, mMinute))
			Toast.makeText(this, "Invalid date or time", Toast.LENGTH_SHORT)
					.show();
		else if (mLocationLat == Integer.MAX_VALUE)
			Toast.makeText(this, "You must set the event's location",
					Toast.LENGTH_SHORT).show();
		else
			return true;
		return false;
	}

	private void updateDisplay() {
		UpdateData(DATE_DIALOG_ID, DateFormat());
		UpdateData(TIME_DIALOG_ID, TimeFormat(TIME_DIALOG_ID));
		UpdateData(DURATION_DIALOG_ID, TimeFormat(DURATION_DIALOG_ID));
		if (!mName.trim().equals(""))
			UpdateData(NAME_DIALOG_ID, mName);
		else
			UpdateData(NAME_DIALOG_ID, "None");
		if (!mDescription.trim().equals(""))
			UpdateData(DESCRIPTION_DIALOG_ID, mDescription);
		else
			UpdateData(DESCRIPTION_DIALOG_ID, "None");
		if (mLocationLat != Integer.MAX_VALUE)
			UpdateData(LOCATION_DIALOG_ID, "Location selected");
		if (!mPrivateEvent)
			UpdateData(PRIVATE_EVENT_DIALOG_ID, "");
		else if (mPassword == null)
			UpdateData(PRIVATE_EVENT_DIALOG_ID, "Password: None");
		else
			UpdateData(PRIVATE_EVENT_DIALOG_ID, "Password: " + mPassword);

		mAdapter.notifyDataSetChanged();
	}

	private String DateFormat() {
		return mDay + "/" + (mMonth + 1) + "/" + mYear;
	}

	private static String pad(int c) {
		if (c >= 10)
			return String.valueOf(c);
		else
			return "0" + String.valueOf(c);
	}

	private String TimeFormat(int Type) {
		if (Type == TIME_DIALOG_ID)
			return pad(mHour) + ":" + pad(mMinute);
		else
			return pad(mDurationHour) + ":" + pad(mDurationMinute);
	}

	private ArrayList<ListItem> buildData() {
		ArrayList<ListItem> list = new ArrayList<CreateEvent.ListItem>();
		list.add(new ListItem("Name", "None"));
		list.add(new ListItem("Description", "None"));
		list.add(new ListItem("Date", ""));
		list.add(new ListItem("Time", ""));
		list.add(new ListItem("Duration (h:m)", ""));
		list.add(new ListItem("Location", "None"));
		list.add(new ListItem("Private Event", ""));
		return list;
	}

	private void UpdateData(int id, String value) {
		mDisplayData.get(id).Value = value;
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		if (id == DATE_DIALOG_ID) {
			DatePickerDialog dpd = (DatePickerDialog) dialog;
			dpd.updateDate(mYear, mMonth, mDay);
		} else if (id == TIME_DIALOG_ID) {
			TimePickerDialog dpd = (TimePickerDialog) dialog;
			dpd.updateTime(mHour, mMinute);
		} else if (id == DURATION_DIALOG_ID) {
			AlertDialog ad = (AlertDialog) dialog;
			TimePicker tp = (TimePicker) ad.findViewById(R.id.timePicker1);
			tp.setCurrentHour(mDurationHour);
			tp.setCurrentMinute(mDurationMinute);
		} else if (id == PRIVATE_EVENT_DIALOG_ID) {

		}
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case NAME_DIALOG_ID:
			return CreateStringPickerDialog(NAME_DIALOG_ID);
		case DESCRIPTION_DIALOG_ID:
			return CreateStringPickerDialog(DESCRIPTION_DIALOG_ID);
		case DATE_DIALOG_ID:
			return new DatePickerDialog(this, mDateSetListener, mYear, mMonth,
					mDay);
		case TIME_DIALOG_ID:
			return new TimePickerDialog(this, mTimeSetListener, mHour, mMinute,
					true);
		case DURATION_DIALOG_ID:
			return CreateDurationPickerDialog();
		case PRIVATE_EVENT_DIALOG_ID:
			return CreateStringPickerDialog(PRIVATE_EVENT_DIALOG_ID);
		}
		return null;
	}

	private AlertDialog CreateStringPickerDialog(final int type) {
		LinearLayout layout = new LinearLayout(this);
		layout.setPadding(DIALOG_PADDING, DIALOG_PADDING, DIALOG_PADDING,
				DIALOG_PADDING);
		final EditText et = new EditText(this);
		et.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));

		layout.addView(et);

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setView(layout);

		if (type == NAME_DIALOG_ID)
			builder.setTitle("Name");
		else if (type == DESCRIPTION_DIALOG_ID)
			builder.setTitle("Description");
		else {
			builder.setTitle("Password");
			et.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
		}

		builder.setPositiveButton("Set", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				if (type == NAME_DIALOG_ID)
					mName = et.getText().toString();
				else if (type == DESCRIPTION_DIALOG_ID)
					mDescription = et.getText().toString();
				else {
					mPassword = et.getText().toString();
					et.setText("");
				}
				updateDisplay();
			}
		});
		builder.setNegativeButton("Cancel", null);
		final AlertDialog ad = builder.create();

		et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus) {
					ad.getWindow()
							.setSoftInputMode(
									WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
				}
			}
		});

		if (type == PRIVATE_EVENT_DIALOG_ID)
			ad.setOnShowListener(new OnShowListener() {

				@Override
				public void onShow(DialogInterface dialog) {
					if (mPassword == null)
						et.setText("");
					else
						et.setText(mPassword);
				}
			});
		et.requestFocus();
		return ad;
	}

	private AlertDialog CreateDurationPickerDialog() {
		LayoutInflater inflater = (LayoutInflater) this
				.getSystemService(LAYOUT_INFLATER_SERVICE);
		View layout = inflater.inflate(R.layout.duration_picker,
				(ViewGroup) findViewById(R.id.root_layout));
		final TimePicker tp = (TimePicker) layout
				.findViewById(R.id.timePicker1);
		tp.setCurrentHour(mDurationHour);
		tp.setCurrentMinute(mDurationMinute);
		tp.setIs24HourView(true);

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setView(layout);
		builder.setTitle("Set duration");
		final Context context = this;
		builder.setPositiveButton("Set", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				if (tp.getCurrentHour() == 0 && tp.getCurrentMinute() == 0) {
					Toast.makeText(context, "Illegal duration",
							Toast.LENGTH_SHORT).show();
					return;
				}
				mDurationHour = tp.getCurrentHour();
				mDurationMinute = tp.getCurrentMinute();
				updateDisplay();
			}
		});
		builder.setNegativeButton("Cancel", null);
		return builder.create();
	}

	public class AddEventTask extends AsyncTask<Event, Void, Void> {

		ProgressDialog mDialog;
		Context mContext;
		boolean mResult;

		public AddEventTask(Context context) {
			mContext = context;
		}

		@Override
		protected Void doInBackground(Event... events) {
			Event newEvent = (Event) events[0];

			mResult = ValtoServices.postEvent(newEvent);

			// ret expected to be true here.

			// at this point the id should be assigned
			if (newEvent.isNew()) {
				mResult = false;
			}
			return null;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			mDialog = ProgressDialog.show(mContext, "", "Creating Event...",
					true);
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			mDialog.dismiss();

			if (mResult) {
				Toast.makeText(mContext, "Event was successfully created",
						Toast.LENGTH_LONG).show();
			} else {
				ErrorHelper.showErrorAlert(mContext, "Event creation failed",
						ValtoServices.getLastServerError());
			}

			finish();

		}
	}

	public class UpdateEventTask extends AsyncTask<Event, Void, Void> {

		ProgressDialog mDialog;
		Context mContext;
		boolean mResult;

		public UpdateEventTask(Context context) {
			mContext = context;
		}

		@Override
		protected Void doInBackground(Event... events) {
			Event updatedEvent = (Event) events[0];

			mResult = ValtoServices.updateEvent(updatedEvent);

			return null;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			mDialog = ProgressDialog.show(mContext, "", "Updating Event...",
					true);
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			mDialog.dismiss();

			mHandler.post(new Runnable() {
				@Override
				public void run() {
					if (mResult) {
						Toast.makeText(mContext,
								"Event was successfully updated",
								Toast.LENGTH_LONG).show();
					} else {
						ErrorHelper.showErrorAlert(mContext,
								"Event update failed",
								ValtoServices.getLastServerError());
					}

					finish();
				}
			});
		}
	}

	public class DeleteEventTask extends AsyncTask<Event, Void, Void> {

		ProgressDialog mDialog;
		Context mContext;
		boolean mResult;

		public DeleteEventTask(Context context) {
			mContext = context;
		}

		@Override
		protected Void doInBackground(Event... events) {
			Event existingEvent = (Event) events[0];

			mResult = ValtoServices.deleteEvent(existingEvent);

			return null;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			mDialog = ProgressDialog.show(mContext, "", "Deleting Event...",
					true);
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			mDialog.dismiss();

			mHandler.post(new Runnable() {
				@Override
				public void run() {
					if (mResult) {
						Toast.makeText(mContext, "Event Deleted.",
								Toast.LENGTH_LONG).show();
					} else {
						ErrorHelper.showErrorAlert(mContext,
								"Delete event failed.",
								ValtoServices.getLastServerError());
					}

					finish();
				}
			});
		}
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) {
			mLocationLat = data.getIntExtra("Lat", Integer.MAX_VALUE);
			mLocationLon = data.getIntExtra("Lon", Integer.MAX_VALUE);
			updateDisplay();
		}
	}

	private class EventsAdapter extends ArrayAdapter<ListItem> {
		private LayoutInflater inflater = null;

		public EventsAdapter(Context context, int textViewResourceId,
				List<ListItem> objects) {
			super(context, textViewResourceId, objects);
			inflater = (LayoutInflater) CreateEvent.this
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		private class ViewHolder {
			public TextView Text1;
			public TextView Text2;
			public CheckBox PrivateEvent;

		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = convertView;
			ViewHolder vh = null;
			if (convertView == null) {
				v = inflater.inflate(R.layout.create_event_item, null);
				vh = new ViewHolder();
				vh.Text1 = (TextView) v.findViewById(R.id.mainText);
				vh.Text2 = (TextView) v.findViewById(R.id.notMainText);
				vh.PrivateEvent = (CheckBox) v
						.findViewById(R.id.PrivateEventCheckBox);
				vh.PrivateEvent
						.setOnCheckedChangeListener(new OnCheckedChangeListener() {
							@Override
							public void onCheckedChanged(
									CompoundButton buttonView, boolean isChecked) {
								if (mPrivateEvent != isChecked) {
									mPrivateEvent = isChecked;
									if (mPrivateEvent)
										showDialog(PRIVATE_EVENT_DIALOG_ID);
									else
										mPassword = null;
									updateDisplay();
								}
							}
						});
				v.setTag(vh);
			}
			vh = (ViewHolder) v.getTag();

			if (position != PRIVATE_EVENT_DIALOG_ID)
				vh.PrivateEvent.setVisibility(View.GONE);
			else
				v.setOnClickListener(new OnClickListener() {

					@Override
					public void onClick(View v) {
						if (mPrivateEvent)
							showDialog(PRIVATE_EVENT_DIALOG_ID);
					}
				});
			vh.PrivateEvent.setChecked(mPrivateEvent);
			ListItem item = getItem(position);
			vh.Text1.setText(item.Title);
			if (item.Value != null)
				vh.Text2.setText(item.Value);

			return v;

		}
	}
}
